import os
# 在import之前设置环境变量
os.environ["NUMPY_DISABLE_CPU_FEATURES"] = "1"  # 禁用CPU特性检测
os.environ["NUMPY_NO_CPU_DISPATCH"] = "1"  # 禁用CPU调度器
import shutil
import threading
import time
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import edge_tts
import asyncio
import sys
import tempfile
import platform
import subprocess
import queue
import re

# 图标和样式定义
DELETE_ICON = "❌"
ADD_ICON = "📁"
CLEAR_ICON = "🗑️"
PROCESS_ICON = "▶️"
FOLDER_ICON = "📂"

# 颜色方案
BACKGROUND = "#f8f9fa"
PRIMARY = "#4e73df"
SECONDARY = "#6c757d"
SUCCESS = "#1cc88a"
INFO = "#36b9cc"
WARNING = "#f6c23e"
DANGER = "#e74a3b"
LIGHT = "#ffffff"
DARK = "#5a5c69"
ACCENT = "#858796"

# 字体设置
TITLE_FONT = ("Segoe UI", 14, "bold")
HEADING_FONT = ("Segoe UI", 10, "bold")
LABEL_FONT = ("Segoe UI", 9)
BUTTON_FONT = ("Segoe UI", 9, "bold")

# 固定语音选项
CHINESE_VOICES = {
    "zh-CN-XiaoxiaoNeural": "女声，自然",
    "zh-CN-YunxiNeural": "男声，自然",
    "zh-CN-YunyangNeural": "男声，新闻播报风格",
    "zh-CN-XiaoxuanNeural": "女声，成熟",
    "zh-CN-YunxiaNeural": "男声，少年",
    "zh-CN-YunjianNeural": "男声，播报解说风格",
    "zh-HK-WanLungNeural": "男生，粤语"
}

def resource_path(relative_path):
    """获取资源的绝对路径，支持打包和开发环境"""
    try:
        # 打包后资源路径
        base_path = sys._MEIPASS
    except Exception:
        # 开发环境路径
        base_path = os.path.abspath(".")
    
    return os.path.join(base_path, relative_path)

class TextToSpeechApp:
    def __init__(self, root):
        self.root = root
        self.root.title("文本转语音工具")
        self.root.geometry("800x650")  # 增加高度以适应新组件
        self.root.configure(bg=BACKGROUND)
        self.root.resizable(True, True)
        
        # 设置应用图标
        self.set_app_icon()
        
        # 创建主框架
        self.main_frame = tk.Frame(root, bg=BACKGROUND)
        self.main_frame.pack(fill="both", expand=True, padx=20, pady=20)
        
        # 创建标题
        self.title_label = tk.Label(
            self.main_frame,
            text="文本转语音工具",
            font=TITLE_FONT,
            bg=BACKGROUND,
            fg=DARK
        )
        self.title_label.pack(pady=(0, 15))
        
        # 创建文件选择区域
        self.create_file_selection()
        
        # 创建文本输入区域
        self.create_text_input()
        
        # 创建控制面板
        self.create_control_panel()
        
        # 创建底部按钮
        self.create_action_buttons()
        
        # 创建状态栏
        self.create_status_bar()
        
        # 状态变量
        self.temp_dir = None
        self.selected_file = None
        self.is_processing = False
        self.stop_processing = False
        self.processing_thread = None
        self.current_file_index = 0
        self.total_chunks = 0
        self.processed_chunks = 0
        
        # 异步任务线程池
        self.task_thread = None
        
        # 创建临时目录
        self.create_temp_dir()
    
    def set_app_icon(self):
        """设置应用图标，支持打包后使用"""
        try:
            icon_path = resource_path('app_icon.ico')
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
            else:
                print(f"图标文件不存在: {icon_path}")
        except Exception as e:
            print(f"设置图标失败: {e}")
    
    def create_temp_dir(self):
        """创建临时目录"""
        try:
            # 使用系统临时目录
            self.temp_dir = tempfile.mkdtemp(prefix="tts_tool_")
            print(f"临时目录创建在: {self.temp_dir}")
            
            # 创建后立即启用打开文件夹按钮
            self.open_folder_button.config(state="normal")
            return True
        except Exception as e:
            print(f"创建临时目录失败: {str(e)}")
            try:
                # 尝试在当前目录创建临时目录
                self.temp_dir = os.path.join(os.getcwd(), "tts_temp")
                os.makedirs(self.temp_dir, exist_ok=True)
                print(f"使用备用临时目录: {self.temp_dir}")
                
                # 创建后立即启用打开文件夹按钮
                self.open_folder_button.config(state="normal")
                return True
            except Exception as e2:
                messagebox.showerror("错误", f"创建临时目录失败: {str(e2)}")
                self.temp_dir = None
                return False
    
    def clear_temp_dir(self):
        """清除临时目录及其内容"""
        if self.temp_dir and os.path.exists(self.temp_dir):
            try:
                # 删除整个临时目录
                shutil.rmtree(self.temp_dir)
                print(f"已清除临时目录: {self.temp_dir}")
                
                # 重新创建临时目录
                return self.create_temp_dir()
            except Exception as e:
                print(f"清除临时目录失败: {str(e)}")
                messagebox.showerror("错误", f"清除临时目录失败: {str(e)}")
                return False
        return True
    
    def create_file_selection(self):
        """创建文件选择区域"""
        file_frame = tk.LabelFrame(
            self.main_frame,
            text="文件输入",
            font=HEADING_FONT,
            bg=LIGHT,
            fg=DARK,
            relief="flat",
            padx=10,
            pady=10
        )
        file_frame.pack(fill="x", pady=(0, 10))
        
        # 文件选择组件
        file_control_frame = tk.Frame(file_frame, bg=LIGHT)
        file_control_frame.pack(fill="x")
        
        # 文件路径标签
        file_label = tk.Label(
            file_control_frame,
            text="选择文件:",
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            width=10,
            anchor="w"
        )
        file_label.pack(side="left")
        
        # 文件路径显示
        self.file_path_var = tk.StringVar()
        self.file_entry = tk.Entry(
            file_control_frame,
            textvariable=self.file_path_var,
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            state="readonly",
            width=50
        )
        self.file_entry.pack(side="left", padx=(5, 0), fill="x", expand=True)
        
        # 浏览按钮
        self.browse_button = tk.Button(
            file_control_frame,
            text="浏览...",
            font=BUTTON_FONT,
            bg=PRIMARY,
            fg=LIGHT,
            activebackground=PRIMARY,
            activeforeground=LIGHT,
            relief="flat",
            command=self.browse_file,
            padx=10,
            pady=3
        )
        self.browse_button.pack(side="left", padx=(10, 0))
        
        # 清除文件按钮
        self.clear_file_button = tk.Button(
            file_control_frame,
            text="清除",
            font=BUTTON_FONT,
            bg=DANGER,
            fg=LIGHT,
            activebackground=DANGER,
            activeforeground=LIGHT,
            relief="flat",
            command=self.clear_file_selection,
            padx=10,
            pady=3,
            state="disabled"
        )
        self.clear_file_button.pack(side="left", padx=(10, 0))
    
    def create_text_input(self):
        # 文本输入框架
        input_frame = tk.LabelFrame(
            self.main_frame,
            text="文本输入",
            font=HEADING_FONT,
            bg=LIGHT,
            fg=DARK,
            relief="flat",
            padx=10,
            pady=10
        )
        input_frame.pack(fill="x", pady=(0, 15))
        
        # 滚动条
        scrollbar = tk.Scrollbar(input_frame)
        scrollbar.pack(side="right", fill="y")
        
        # 文本输入框
        self.text_entry = tk.Text(
            input_frame,
            height=10,
            wrap="word",
            yscrollcommand=scrollbar.set,
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            padx=10,
            pady=10
        )
        self.text_entry.pack(fill="x")
        
        # 配置滚动条
        scrollbar.config(command=self.text_entry.yview)
        
        # 占位文本
        self.placeholder = "在此输入您要转换为语音的文本..."
        self.text_entry.insert("1.0", self.placeholder)
        self.text_entry.config(fg=SECONDARY)
        
        # 绑定事件
        self.text_entry.bind("<FocusIn>", self.on_text_focusin)
        self.text_entry.bind("<FocusOut>", self.on_text_focusout)
    
    def create_control_panel(self):
        # 控制面板框架
        control_frame = tk.LabelFrame(
            self.main_frame,
            text="语音设置",
            font=HEADING_FONT,
            bg=LIGHT,
            fg=DARK,
            relief="flat",
            padx=10,
            pady=10
        )
        control_frame.pack(fill="x", pady=(0, 15))
        
        # 语音选择
        voice_frame = tk.Frame(control_frame, bg=LIGHT)
        voice_frame.pack(fill="x", pady=(0, 10))
        
        voice_label = tk.Label(
            voice_frame,
            text="选择语音:",
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            width=10,
            anchor="w"
        )
        voice_label.pack(side="left")
        
        self.voice_var = tk.StringVar()
        
        # 创建带描述的语音选项列表
        voice_options = []
        for voice_id, description in CHINESE_VOICES.items():
            voice_options.append(f"{voice_id} - {description}")
        
        self.voice_combo = ttk.Combobox(
            voice_frame,
            textvariable=self.voice_var,
            font=LABEL_FONT,
            state="readonly",
            width=50
        )
        self.voice_combo['values'] = voice_options
        self.voice_combo.current(0)  # 默认选择第一个
        self.voice_combo.pack(side="left", padx=(5, 0), fill="x", expand=True)
        
        # 语速控制
        rate_frame = tk.Frame(control_frame, bg=LIGHT)
        rate_frame.pack(fill="x", pady=(0, 10))
        
        rate_label = tk.Label(
            rate_frame,
            text="语速调节:",
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            width=10,
            anchor="w"
        )
        rate_label.pack(side="left")
        
        self.rate_var = tk.StringVar(value="+0%")
        self.rate_slider = ttk.Scale(
            rate_frame,
            from_=0,
            to=100,
            orient="horizontal",
            command=self.update_rate_label
        )
        self.rate_slider.set(0)
        self.rate_slider.pack(side="left", padx=(5, 10), fill="x", expand=True)
        
        rate_value = tk.Label(
            rate_frame,
            textvariable=self.rate_var,
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            width=5,
            anchor="w"
        )
        rate_value.pack(side="right")
        
        # 分段设置
        chunk_frame = tk.Frame(control_frame, bg=LIGHT)
        chunk_frame.pack(fill="x", pady=(10, 0))
        
        chunk_label = tk.Label(
            chunk_frame,
            text="分段设置:",
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK,
            width=10,
            anchor="w"
        )
        chunk_label.pack(side="left")
        
        # 每段最大长度
        tk.Label(
            chunk_frame,
            text="每段字数:",
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK
        ).pack(side="left", padx=(0, 5))
        
        self.chunk_size_var = tk.IntVar(value=1500)
        chunk_size_spin = tk.Spinbox(
            chunk_frame,
            from_=100,
            to=2000,
            increment=50,
            textvariable=self.chunk_size_var,
            width=6,
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK
        )
        chunk_size_spin.pack(side="left", padx=(0, 10))
        
        # 每次处理段数
        tk.Label(
            chunk_frame,
            text="每次处理段数:",
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK
        ).pack(side="left", padx=(10, 5))
        
        self.batch_size_var = tk.IntVar(value=4)
        batch_size_spin = tk.Spinbox(
            chunk_frame,
            from_=1,
            to=10,
            increment=1,
            textvariable=self.batch_size_var,
            width=3,
            font=LABEL_FONT,
            bg=LIGHT,
            fg=DARK
        )
        batch_size_spin.pack(side="left")
    
    def create_status_bar(self):
        """创建状态栏"""
        status_frame = tk.Frame(self.main_frame, bg=BACKGROUND)
        status_frame.pack(fill="x", pady=(10, 0))
        
        # 进度标签
        self.status_var = tk.StringVar(value="就绪")
        self.status_label = tk.Label(
            status_frame,
            textvariable=self.status_var,
            font=LABEL_FONT,
            bg=BACKGROUND,
            fg=PRIMARY,
            anchor="w"
        )
        self.status_label.pack(side="left", fill="x", expand=True)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(
            status_frame,
            variable=self.progress_var,
            orient="horizontal",
            length=200,
            mode="determinate"
        )
        self.progress_bar.pack(side="right")
    
    def create_action_buttons(self):
        # 按钮框架
        button_frame = tk.Frame(self.main_frame, bg=BACKGROUND)
        button_frame.pack(fill="x", pady=(10, 0))
        
        # 生成按钮
        self.generate_button = tk.Button(
            button_frame,
            text=f" {PROCESS_ICON} 生成语音",
            font=BUTTON_FONT,
            bg=SUCCESS,
            fg=LIGHT,
            activebackground=SUCCESS,
            activeforeground=LIGHT,
            relief="flat",
            command=self.generate_audio,
            padx=15,
            pady=8
        )
        self.generate_button.pack(side="left", padx=(0, 10))
        
        # 停止按钮
        self.stop_button = tk.Button(
            button_frame,
            text=f" ⏹️ 停止",
            font=BUTTON_FONT,
            bg=DANGER,
            fg=LIGHT,
            activebackground=DANGER,
            activeforeground=LIGHT,
            relief="flat",
            command=self.stop_processing,
            padx=15,
            pady=8,
            state="disabled"
        )
        self.stop_button.pack(side="left", padx=(0, 10))
        
        # 打开文件夹按钮 - 创建后立即启用
        self.open_folder_button = tk.Button(
            button_frame,
            text=f" {FOLDER_ICON} 打开文件夹",
            font=BUTTON_FONT,
            bg=PRIMARY,
            fg=LIGHT,
            activebackground=PRIMARY,
            activeforeground=LIGHT,
            relief="flat",
            command=self.open_temp_folder,
            padx=15,
            pady=8,
            state="disabled"  # 初始为禁用，创建临时文件夹后启用
        )
        self.open_folder_button.pack(side="left", padx=(0, 10))
        
        # 清除按钮
        self.clear_button = tk.Button(
            button_frame,
            text=f" {CLEAR_ICON} 清除",
            font=BUTTON_FONT,
            bg=DANGER,
            fg=LIGHT,
            activebackground=DANGER,
            activeforeground=LIGHT,
            relief="flat",
            command=self.clear_input,
            padx=15,
            pady=8
        )
        self.clear_button.pack(side="right", padx=(0, 10))
    
    def browse_file(self):
        """浏览并选择文件"""
        file_path = filedialog.askopenfilename(
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if file_path:
            self.selected_file = file_path
            self.file_path_var.set(os.path.basename(file_path))
            self.clear_file_button.config(state="normal")
            
            # 禁用文本输入框
            self.text_entry.config(state="disabled")
            self.text_entry.config(bg="#f0f0f0")
    
    def clear_file_selection(self):
        """清除文件选择"""
        self.selected_file = None
        self.file_path_var.set("")
        self.clear_file_button.config(state="disabled")
        
        # 启用文本输入框
        self.text_entry.config(state="normal")
        self.text_entry.config(bg=LIGHT)
        self.on_text_focusout(None)  # 恢复占位文本
    
    def on_text_focusin(self, event):
        if self.text_entry.get("1.0", "end-1c") == self.placeholder:
            self.text_entry.delete("1.0", "end")
            self.text_entry.config(fg=DARK)
    
    def on_text_focusout(self, event):
        if not self.text_entry.get("1.0", "end-1c").strip():
            self.text_entry.insert("1.0", self.placeholder)
            self.text_entry.config(fg=SECONDARY)
    
    def update_rate_label(self, value):
        self.rate_var.set(f"{int(float(value))}%")
    
    def get_selected_voice_id(self):
        """从组合框中提取语音ID"""
        selected = self.voice_var.get()
        if selected:
            # 提取语音ID部分（组合框选项格式为 "voice_id - description"）
            return selected.split(" - ")[0]
        return "zh-CN-XiaoxiaoNeural"  # 默认值
    
    def generate_audio(self):
        """生成语音的入口函数"""
        if self.is_processing:
            return
            
        # 确保临时目录存在
        if not self.temp_dir:
            if not self.create_temp_dir():
                messagebox.showerror("错误", "无法创建临时目录")
                return
        
        # 检查输入源
        text_input = self.text_entry.get("1.0", "end-1c").strip()
        if self.selected_file:
            # 文件模式
            self.process_file()
        elif text_input and text_input != self.placeholder:
            # 文本模式
            self.process_text(text_input)
        else:
            messagebox.showwarning("输入为空", "请选择文件或输入文本")
    
    def process_text(self, text):
        """处理直接输入的文本"""
        # 更新UI状态
        self.is_processing = True
        self.stop_processing = False
        self.generate_button.config(state="disabled")
        self.stop_button.config(state="normal")
        self.status_var.set("正在生成音频...")
        self.progress_var.set(0)
        
        # 获取语音设置
        voice_id = self.get_selected_voice_id()
        rate = int(self.rate_slider.get())
        
        # 生成文件名
        timestamp = int(time.time())
        output_file = os.path.join(self.temp_dir, f"output_{timestamp}.mp3")
        
        # 在新线程中生成音频
        def generate_in_thread():
            try:
                # 设置事件循环策略（解决Windows打包问题）
                if platform.system() == 'Windows':
                    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
                
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)
                
                communicate = edge_tts.Communicate(text, voice_id, rate=f"+{rate}%")
                loop.run_until_complete(communicate.save(output_file))
                
                self.root.after(0, lambda: self.on_generation_complete(output_file))
            
            except Exception as e:
                self.root.after(0, lambda: self.on_generation_error(f"生成错误: {str(e)}"))
            finally:
                self.root.after(0, self.reset_processing_state)
        
        threading.Thread(target=generate_in_thread, daemon=True).start()
    
    def process_file(self):
        """处理选定的文件"""
        if not self.selected_file or not os.path.exists(self.selected_file):
            messagebox.showwarning("文件错误", "请选择一个有效的文本文件")
            return
        
        # 更新UI状态
        self.is_processing = True
        self.stop_processing = False
        self.generate_button.config(state="disabled")
        self.stop_button.config(state="normal")
        self.status_var.set("正在准备处理文件...")
        self.progress_var.set(0)
        self.current_file_index = 0
        self.processed_chunks = 0
        self.total_chunks = 0
        
        # 获取语音设置
        voice_id = self.get_selected_voice_id()
        rate = int(self.rate_slider.get())
        
        # 获取处理参数
        chunk_size = self.chunk_size_var.get()
        batch_size = self.batch_size_var.get()
        
        # 在新线程中处理文件
        def process_in_thread():
            try:
                # 设置事件循环策略
                if platform.system() == 'Windows':
                    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
                
                # 创建临时目录用于存储分段文件
                chunk_dir = os.path.join(self.temp_dir, "chunks")
                os.makedirs(chunk_dir, exist_ok=True)
                
                # 计算文件总段数
                self.total_chunks = self.calculate_chunks(self.selected_file, chunk_size)
                self.root.after(0, lambda: self.status_var.set(f"0/{self.total_chunks} 段已处理"))
                
                # 逐批处理文件
                with open(self.selected_file, 'r', encoding='utf-8') as f:
                    while True:
                        if self.stop_processing:
                            break
                            
                        # 读取一批片段
                        chunks = self.read_next_chunks(f, chunk_size, batch_size)
                        if not chunks:
                            break
                            
                        # 处理当前批次的片段
                        self.process_chunk_batch(chunks, voice_id, rate, chunk_dir)
                        
                        # 更新进度
                        self.processed_chunks += len(chunks)
                        progress = (self.processed_chunks / self.total_chunks) * 100
                        self.root.after(0, lambda: self.progress_var.set(progress))
                        self.root.after(0, lambda: self.status_var.set(
                            f"{self.processed_chunks}/{self.total_chunks} 段已处理"
                        ))
                        
                        # 稍微延迟以避免UI卡顿
                        time.sleep(0.1)
                
                if not self.stop_processing:
                    self.root.after(0, self.on_file_processing_complete)
            
            except Exception as e:
                self.root.after(0, lambda: self.on_generation_error(f"文件处理错误: {str(e)}"))
            finally:
                self.root.after(0, self.reset_processing_state)
        
        self.processing_thread = threading.Thread(target=process_in_thread, daemon=True)
        self.processing_thread.start()
    
    def calculate_chunks(self, file_path, chunk_size):
        """计算文件需要分多少段"""
        chunk_count = 0
        with open(file_path, 'r', encoding='utf-8') as f:
            while True:
                chunk = self.read_next_chunk(f, chunk_size)
                if not chunk:
                    break
                chunk_count += 1
        return chunk_count
    
    def read_next_chunk(self, file, max_length):
        """从文件中读取下一个片段"""
        chunk = ""
        while len(chunk) < max_length:
            line = file.readline()
            if not line:
                break
            chunk += line
            
            # 如果超过最大长度，尝试在标点处分割
            if len(chunk) >= max_length:
                # 查找最近的标点符号
                last_punctuation = max(
                    chunk.rfind('。'), 
                    chunk.rfind('！'),
                    chunk.rfind('？'),
                    chunk.rfind('；'),
                    chunk.rfind('\n'),
                    chunk.rfind('.'),
                    chunk.rfind('!'),
                    chunk.rfind('?'),
                    chunk.rfind(';')
                )
                
                if last_punctuation > max_length * 0.5:  # 确保不会切得太短
                    # 回退文件指针
                    file.seek(file.tell() - (len(chunk) - last_punctuation - 1))
                    chunk = chunk[:last_punctuation + 1]
                    break
        
        return chunk.strip()
    
    def read_next_chunks(self, file, chunk_size, batch_size):
        """读取下一批片段"""
        chunks = []
        for _ in range(batch_size):
            chunk = self.read_next_chunk(file, chunk_size)
            if chunk:
                chunks.append(chunk)
            else:
                break
        return chunks
    
    def process_chunk_batch(self, chunks, voice_id, rate, output_dir):
        """处理一批文本片段"""
        threads = []
        results = queue.Queue()
        
        # 为每个片段创建一个线程
        for i, chunk in enumerate(chunks):
            thread = threading.Thread(
                target=self.generate_chunk_audio,
                args=(chunk, voice_id, rate, output_dir, self.current_file_index + i, results)
            )
            thread.start()
            threads.append(thread)
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        # 检查结果
        while not results.empty():
            result = results.get()
            if result.startswith("ERROR:"):
                raise Exception(result[6:])
        
        # 更新文件索引
        self.current_file_index += len(chunks)
    
    def generate_chunk_audio(self, text, voice_id, rate, output_dir, index, result_queue):
        """生成单个片段的音频"""
        try:
            # 创建每个线程自己的事件循环
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            
            output_file = os.path.join(output_dir, f"chunk_{index:04d}.mp3")
            communicate = edge_tts.Communicate(text, voice_id, rate=f"+{rate}%")
            loop.run_until_complete(communicate.save(output_file))
            result_queue.put("OK")
        except Exception as e:
            result_queue.put(f"ERROR:{str(e)}")
        finally:
            loop.close()
    
    def on_generation_complete(self, output_file):
        self.reset_processing_state()
        messagebox.showinfo("生成成功", f"音频文件已生成:\n{os.path.basename(output_file)}")
    
    def on_file_processing_complete(self):
        self.reset_processing_state()
        messagebox.showinfo("处理完成", f"文件处理完成！共生成 {self.processed_chunks} 个音频片段")
    
    def on_generation_error(self, error):
        self.reset_processing_state()
        messagebox.showerror("错误", error)
    
    def reset_processing_state(self):
        self.is_processing = False
        self.stop_processing = False
        self.generate_button.config(state="normal")
        self.stop_button.config(state="disabled")
        self.status_var.set("就绪")
    
    def stop_processing(self):
        self.stop_processing = True
        self.stop_button.config(state="disabled")
        self.status_var.set("正在停止...")
    
    def open_temp_folder(self):
        """打开临时文件夹"""
        if self.temp_dir and os.path.exists(self.temp_dir):
            try:
                # 根据操作系统使用不同的命令打开文件夹
                if platform.system() == "Windows":
                    os.startfile(self.temp_dir)
                elif platform.system() == "Darwin":  # macOS
                    subprocess.Popen(["open", self.temp_dir])
                else:  # Linux
                    subprocess.Popen(["xdg-open", self.temp_dir])
            except Exception as e:
                messagebox.showerror("打开错误", f"无法打开文件夹: {str(e)}")
        else:
            messagebox.showwarning("无临时目录", "临时目录尚未创建或已被删除")
    
    def clear_input(self):
        """清除输入并删除临时文件夹"""
        # 清除文本输入
        self.text_entry.config(state="normal")
        self.text_entry.delete("1.0", "end")
        self.text_entry.insert("1.0", self.placeholder)
        self.text_entry.config(fg=SECONDARY)
        
        # 清除文件选择
        self.clear_file_selection()
        
        # 清除临时文件夹
        if self.clear_temp_dir():
            messagebox.showinfo("清除完成", "已清除所有输入和临时文件")
        
        # 重置状态栏
        self.status_var.set("就绪")
        self.progress_var.set(0)
    
    def on_closing(self):
        # 如果正在处理，先停止
        if self.is_processing:
            self.stop_processing = True
            time.sleep(1)  # 给线程一点时间停止
        
        # 清理临时目录
        if self.temp_dir and os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
                print(f"已清理临时目录: {self.temp_dir}")
            except Exception as e:
                print(f"清理临时目录失败: {e}")
        self.root.destroy()


if __name__ == "__main__":
    # 设置事件循环策略（解决Windows打包问题）
    if platform.system() == 'Windows':
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    
    root = tk.Tk()
    app = TextToSpeechApp(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()